#pragma once
#include<iostream>
#include<string>
#include<unordered_map>
#include<memory>

#include"Connection.hpp"
#include"Epoller.hpp"


//connection容器-负责管理connection和对应的内核事件以及事件派发
class Reactor
{
static const int gnum=64;
public:
    Reactor():_epoller(std::make_unique<Epoller>()),_isrunning(false)
    {}
    void AddConnection(int fd,uint32_t events,const InetAddr addr,int type)
    {
        //构建链接
        Connection* conn=new Connection(fd);
        conn->SetEvents(events);
        conn->SetReactor(this);//将当前对象设置进所有conn中
        conn->SetAddr(addr);
        conn->SetConnectionType(type);
        if(conn->Type()==ListenConnection)
        {
            conn->RegisterHandler(_OnConnect,nullptr,nullptr);
        }
        else
        {
            conn->RegisterHandler(_OnRecver,_OnSender,_OnExcepter);
        }
        //将fd和events写透到内存
        if(!_epoller->AddEvent(conn->Sockfd(),conn->GetEvents()))return;
        //托管链接
        _connections.insert(std::make_pair(fd,conn));   
    }
    void EnableConnectionReadWrite(int sockfd,bool read,bool write)
    {
        if(!IsConnectionExists(sockfd))return;
        //修改管理的数据
        uint32_t events=((read?EPOLLIN:0)|(write?EPOLLOUT:0)|EPOLLET);
        _connections[sockfd]->SetEvents(events);
        //写入内核
        _epoller->ModEvent(_connections[sockfd]->Sockfd(),_connections[sockfd]->GetEvents());
    }
    void DelConnection(int sockfd)
    {
        if(!IsConnectionExists(sockfd))return;

        //解除epoll对应的fd关心，对应的文件描述符释放，移除Reactor中的connection
        LOG(INFO,"sockfd:%d quit 服务器释放对应资源\n",sockfd);
        _epoller->DelEvent(sockfd);
        _connections[sockfd]->Close();
        delete _connections[sockfd];
        _connections.erase(sockfd);
    }
    void LoopOnce(int timeout)
    {
        int n=_epoller->Wait(_revs,gnum,timeout);
            for(int i=0;i<n;i++)
            {
                int sockfd=_revs[i].data.fd;
                uint32_t revents=_revs[i].events;
                if(revents & EPOLLERR)revents |=(EPOLLIN | EPOLLOUT);//出错返回将其放在读写中统一处理
                if(revents & EPOLLHUP)revents |=(EPOLLIN | EPOLLOUT);//对方挂断了
                
                if(revents & EPOLLIN)
                {
                    if(IsConnectionExists(sockfd)&&_connections[sockfd]->_handler_recver)//判断是否有回调函数
                    {
                        _connections[sockfd]->_handler_recver(_connections[sockfd]);//将事件派发给对应链接
                    }
                }
                if(revents & EPOLLOUT)
                {
                    if(IsConnectionExists(sockfd)&&_connections[sockfd]->_handler_sender)
                    {
                        _connections[sockfd]->_handler_sender(_connections[sockfd]);
                    }
                }
            }
    }
    void Dispatcher()//事件派发
    {
        int timeout = -1;
        _isrunning=true;
        while(_isrunning)
        {
            LoopOnce(timeout);
            PrintfDebug();
        }
        _isrunning=false;
    }
    bool IsConnectionExists(int fd)
    {
        return _connections.find(fd)!=_connections.end();
    }
    void SetConnectHandler(handler_t connect)
    {
        _OnConnect = connect;
    }
    void SetNormalHandler(handler_t recver,handler_t sender,handler_t excepter)
    {
        _OnRecver = recver;
        _OnSender = sender;
        _OnExcepter = excepter;
    }
    void PrintfDebug()
    {
        std::string fdlist;
        for(auto& conn:_connections)
        {
            fdlist+=(std::to_string(conn.second->Sockfd())+" ");
        }
        LOG(DEBUG,"epoll管理的fd列表:%s\n",fdlist.c_str());
    }
    ~Reactor(){}
private:
    std::unordered_map<int,Connection*> _connections;//key-sockfd  val-Connection*
    std::unique_ptr<Multiplex> _epoller;
    bool _isrunning;

    struct epoll_event _revs[gnum];

    //sock处理方法集
    //处理链接请求
    handler_t _OnConnect;
    //处理普通socket
    handler_t _OnRecver;
    handler_t _OnSender;
    handler_t _OnExcepter;
};